using System;
using System.Security;
using System.ComponentModel;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace pixtek.browser
{
  /// <summary>
  /// An extended version of the <see cref="WebBrowser"/> control.
  /// </summary>
  public class ExtendedWebBrowser : System.Windows.Forms.WebBrowser
  {
    System.Windows.Forms.AxHost.ConnectionPointCookie cookie;
    WebBrowserExtendedEvents events;

    private UnsafeNativeMethods.IWebBrowser2 axIWebBrowser2;
    
    /// <summary>
    /// This method supports the .NET Framework infrastructure and is not intended to be used directly from your code. 
    /// Called by the control when the underlying ActiveX control is created. 
    /// </summary>
    /// <param name="nativeActiveXObject"></param>
    protected override void AttachInterfaces(object nativeActiveXObject)
    {
      this.axIWebBrowser2 = (UnsafeNativeMethods.IWebBrowser2)nativeActiveXObject;
      base.AttachInterfaces(nativeActiveXObject);
    }

    // UnsafeNativeMethods.IDocHostUIHandler iDocHostUIHandler;

    /// <summary>
    /// This method supports the .NET Framework infrastructure and is not intended to be used directly from your code. 
    /// Called by the control when the underlying ActiveX control is discarded. 
    /// </summary>
    protected override void DetachInterfaces()
    {
      this.axIWebBrowser2 = null;
      base.DetachInterfaces();
    }

    /// <summary>
    /// This method will be called to give you a chance to create your own event sink
    /// </summary>
    protected override void CreateSink()
    {
      //MAKE SURE TO CALL THE BASE or the normal events won't fire
      base.CreateSink();
      events = new WebBrowserExtendedEvents(this);
      cookie = new System.Windows.Forms.AxHost.ConnectionPointCookie(this.ActiveXInstance, events, typeof(UnsafeNativeMethods.DWebBrowserEvents2));
    }

    /// <summary>
    /// Detaches the event sink
    /// </summary>
    protected override void DetachSink()
    {
      if (null != cookie)
      {
        cookie.Disconnect();
        cookie = null;
      }
      base.DetachSink();
    }

    internal object Application
    {
      get { return axIWebBrowser2.Application; }
    }

    /// <summary>
    /// Fires before navigation occurs in the given object (on either a window or frameset element).
    /// </summary>
    public event EventHandler<BrowserExtendedNavigatingEventArgs> BeforeNavigate;
    /// <summary>
    /// Raised when a new window is to be created. Extends DWebBrowserEvents2::NewWindow2 with additional information about the new window.
    /// </summary>
    public event EventHandler<BrowserExtendedNavigatingEventArgs> BeforeNewWindow;

    /// <summary>
    /// 
    /// </summary>
    /// <param name="pDisp">[in, out] Address of an interface pointer that, optionally, receives the IDispatch interface pointer of a new WebBrowser or InternetExplorer object.</param>
    /// <param name="url">[in] URL being opened in the new window.</param>
    /// <param name="flags">[in] Flags from the <see cref="UrlContext"/> enumeration that pertain to the new window.</param>
    /// <param name="cancel">[in, out] VARIANT_BOOL value to determine whether the current navigation should be canceled.</param>
    protected void OnBeforeNewWindow(ref object pDisp, string url, UrlContext flags, out bool cancel)
    {
      // EventHandler<WebBrowserExtendedNavigatingEventArgs> h = BeforeNewWindow;
      BrowserExtendedNavigatingEventArgs args = new BrowserExtendedNavigatingEventArgs(ref pDisp, url, null, flags);
      if (BeforeNewWindow != null)
      {
        BeforeNewWindow(this, args);
      }
      cancel = args.Cancel;
      pDisp = args.pDisp;
    }

    /// <summary>
    /// Raises the <see cref="BeforeNavigate"/> event
    /// </summary>
    /// <param name="pDisp">[in] Pointer to the IDispatch interface for the WebBrowser object that represents the window or frame. This interface can be queried for the IWebBrowser2 interface. </param>
    /// <param name="url">[in] Pointer to a VARIANT structure of type VT_BSTR that contains the URL to be navigated to.</param>
    /// <param name="frame">[in] Pointer to a VARIANT structure of type VT_BSTR that contains the name of the frame in which to display the resource, or NULL if no named frame is targeted for the resource. </param>
    /// <param name="cancel">[in, out] Pointer to a VARIANT structure of type VARIANT_BOOL that contains the cancel flag. An application can set this parameter to VARIANT_TRUE to cancel the navigation operation, or to VARIANT_FALSE to allow it to proceed. </param>
    protected void OnBeforeNavigate(object pDisp, string url, string frame, out bool cancel)
    {
      EventHandler<BrowserExtendedNavigatingEventArgs> h = BeforeNavigate;
      BrowserExtendedNavigatingEventArgs args = new BrowserExtendedNavigatingEventArgs(ref pDisp, url, frame, UrlContext.None);
      if (null != h)
      {
        h(this, args);
      }
      //Pass the cancellation chosen back out to the events
      cancel = args.Cancel;
      pDisp = args.pDisp;
    }
    //This class will capture events from the WebBrowser
    class WebBrowserExtendedEvents : System.Runtime.InteropServices.StandardOleMarshalObject, UnsafeNativeMethods.DWebBrowserEvents2
    {
      ExtendedWebBrowser _Browser;
      public WebBrowserExtendedEvents(ExtendedWebBrowser browser) { _Browser = browser; }

      #region DWebBrowserEvents2 Members

      //Implement whichever events you wish
      void UnsafeNativeMethods.DWebBrowserEvents2.BeforeNavigate2(object pDisp, ref object URL, ref object flags, ref object targetFrameName, ref object postData, ref object headers, ref bool cancel)
      {
        _Browser.OnBeforeNavigate(pDisp, (string)URL, (string)targetFrameName, out cancel);
      }

      void UnsafeNativeMethods.DWebBrowserEvents2.NewWindow3(ref object pDisp, ref bool cancel, ref object flags, ref object URLContext, ref object URL)
      {
        try
        {
          _Browser.OnBeforeNewWindow(ref pDisp, (string)URL, (UrlContext)flags, out cancel);
        }
        catch (Exception ex)
        {
          MessageBox.Show(ex.ToString());
        }
      }

      #endregion
    }
  }



}
